<?php

class DarknessMessageUtil {
    /**
     * Returns the count of all the messages a character has
     * @param $character
     * @return integer count of messages
     */
    static function countMessages(Character $character){
        $sql = 'SELECT count(*) as count FROM messages
                                WHERE receiver IN (?, ?) AND
                                      receiverType = ? AND
                                      substr(hide,3,1) = 0';
        $res = db_prepare($sql, $character->handle, $character->entityID, $character->entityType);

        return db_single_result($res);
    }

    /**
     * Returns messages sent to $character
     * @param $character
     * @return array of DM objects
     */
    static function getMessages(Character $character){
        $sql = 'SELECT * FROM messages
                        WHERE receiver IN (?, ?) AND
                              receiverType = ? AND
                              substr(hide,3,1) = 0
                        ORDER BY date DESC, messageID DESC';
        $res = db_prepare($sql, $character->handle, $character->entityID, $character->entityType);

        return db_get_rows($res, 'DM');
    }

    /**
     * Only returns messages after a given date
     * @param $character
     * @param $after cgt timestamp for latest
     * @return array of DM objects
     */
    static function getNewMessages(Character $character, $after){
        $messages = DMUtil::getMessages($character);
        return array_filter($messages, function($message) use ($after){
            return $message->date >= $after;
        });
    }

    /**
     * Gets all messages sent by a character
     * @param $character
     * @return array of DM objects
     */
    static function getSentMessages(Character $character){
        $res = db_prepare('SELECT * FROM messages
                           WHERE senderType = #cint_ENTITYTYPE_CHARACTER AND
                                 receiverType = #cint_ENTITYTYPE_CHARACTER AND
                                 sender IN (?, ?) AND
                                 hide NOT IN("0;1", "1;1")
                           ORDER BY date DESC',
                           $character->entityID, $character->handle);
        $messages = db_get_rows($res, 'DM');

        foreach($messages as &$message){
        	$message->subject = HTMLUtil::cleanInput($message->subject);
            $message->communication = HTMLUtil::cleanInput($message->communication);
            $message->sender = $character;
            $message->receiver = getEntityInfo($message->receiver, cint_ENTITYTYPE_CHARACTER);
        }

        return $messages;
    }

    /**
     * Gets all messages between two parties
     * @param $a
     * @param $b
     */
    static function getDialogMessages(Character $a, Character $b){
        $sql = 'SELECT * FROM messages
                WHERE receiverType = #cint_ENTITYTYPE_CHARACTER AND
                      senderType = #cint_ENTITYTYPE_CHARACTER AND
                      ((receiver IN (@aid, @ahand) AND sender IN (@bid, @bhand)) OR
                       (receiver IN (@bid, @bhand) AND sender IN (@aid, @ahand)))
                ORDER BY date DESC';
        $res = db_prepare($sql, array('aid'   => $a->entityID,
                                      'ahand' => $a->handle,
                                      'bid'   => $b->entityID,
                                      'bhand' => $b->handle));
        $messages = db_get_rows($res);

        foreach($messages as &$message){
            $message->communication = HTMLUtil::cleanInput($message->communication);

            //saves us looking them up again, they will always be a->b or b->a
            if(in_array($message->sender, array($a->entityID, $a->handle))){
                $message->sender = $a;
                $message->receiver = $b;
            } else {
                $message->receiver = $a;
                $message->sender = $b;
            }
        }

        return $messages;
    }


    /**
     * Gets a single message to or from a character by their messageID
     * @param Character $character
     * @param integer $messageID
     * @return message stdClass object or null
     */
    static function getMessageById(Character $character, integer $messageID) {
    	$sql = 'SELECT * FROM messages
                        WHERE ((receiver IN (?, ?) AND substr(hide,3,1) = 0 AND receiverType = ?)
                              	OR (sender IN (?, ?) AND substr(hide,1,1) = 0 AND senderType = ?)) AND
                              messageID = ? AND
                              substr(hide,3,1) = 0
                        LIMIT 1';
        $res = db_prepare($sql, $character->handle, $character->entityID, $character->entityType, $character->handle, $character->entityID, $character->entityType, $messageID);

        if(($message = db_fetch_object($res)) instanceof stdClass) {
        	return $message;
        }
        return null;
    }
        
    /**
     * Returns the count of all the messages a character has
     * @param $character
     * @return integer count of messages
     */
    static function countMessagesBetween(Character $characterA, Character $characterB, enumDMDeliveryType $deliveryType){
    	if ($characterA == null && $characterB == null) {
    		throw new CombineException('Invalid arguments supplied.');
    	}
    	
    	$receiver = '';
    	$sender = '';
    	$values = array();
    	
    	if ($characterA != null) {
    		if ($deliveryType & enumDMDeliveryType::Received) $receiver = 'receiver IN (@idA, @handleA)';
    		if ($deliveryType & enumDMDeliveryType::Sent) $sender = 'sender IN (@idA, @handleA)';
    		$values['handleA'] = $characterA->handle;
    		$values['idA'] = $characterA->entityID;
    	}
    	
    	if ($characterB != null) {
    		if ($characterA != null) {
    			if ($deliveryType & enumDMDeliveryType::Received) $receiver .= ' AND ';
    			if ($deliveryType & enumDMDeliveryType::Sent) $sender = ' AND '.$sender;
    		}
    		
    		if ($deliveryType & enumDMDeliveryType::Received) $receiver .= ' sender IN (@idB, @handleB)';
    		if ($deliveryType & enumDMDeliveryType::Sent) $sender = 'receiver IN (@idB, @handleB) '.$sender;
    		$values['handleB'] = $characterB->handle;
    		$values['idB'] = $characterB->entityID;
    	}
    	
    	if (strlen($receiver) > 0 && strlen($sender) > 0) {
    		$filter = $receiver.' OR '.$sender;
    	} else {
    		$filter = $receiver.$sender;
    	}
    	
    	$sql = 'SELECT count(*) as count FROM messages
		    	WHERE receiverType = #cint_ENTITYTYPE_CHARACTER AND
                      senderType = #cint_ENTITYTYPE_CHARACTER AND ('.
    				  $filter.
		    	') ORDER BY date DESC, messageID DESC';
    	
    	$res = db_prepare( $sql, $values );

    	return db_single_result($res);
    }
    
    
    /**
     * Returns messages sent to or received by $character
     * @param $characterA
     * @param $characterB
     * @param $page
     * @param $perPage
     * @return array of DM objects
     */
    static function getMessagesBetween(Character $characterA, Character $characterB, enumDMDeliveryType $deliveryType, integer $page, integer $perPage){
    	if ($characterA == null && $characterB == null) {
    		throw new CombineException('Invalid arguments supplied.');
    	}
    	
    	$receiver = '';
    	$sender = '';
    	$values = array();
    	
    	if ($characterA != null) {
    		if ($deliveryType & enumDMDeliveryType::Received) $receiver = 'receiver IN (@idA, @handleA)';
    		if ($deliveryType & enumDMDeliveryType::Sent) $sender = 'sender IN (@idA, @handleA)';
    		$values['handleA'] = $characterA->handle;
    		$values['idA'] = $characterA->entityID;
    	}
    	
    	if ($characterB != null) {
    		if ($characterA != null) {
    			if ($deliveryType & enumDMDeliveryType::Received) $receiver .= ' AND ';
    			if ($deliveryType & enumDMDeliveryType::Sent) $sender = ' AND '.$sender;
    		}
    		
    		if ($deliveryType & enumDMDeliveryType::Received) $receiver .= ' sender IN (@idB, @handleB)';
    		if ($deliveryType & enumDMDeliveryType::Sent) $sender = 'receiver IN (@idB, @handleB) '.$sender;
    		$values['handleB'] = $characterB->handle;
    		$values['idB'] = $characterB->entityID;
    	}
    	
    	if (strlen($receiver) > 0 && strlen($sender) > 0) {
    		$filter = $receiver.' OR '.$sender;
    	} else {
    		$filter = $receiver.$sender;
    	}
    	
    	$sql = 'SELECT * FROM messages
		    	WHERE receiverType = #cint_ENTITYTYPE_CHARACTER AND
                      senderType = #cint_ENTITYTYPE_CHARACTER AND ('.
                      $filter.
		    	') ORDER BY date DESC, messageID DESC';
    	
    	$sql = db_prepare_assoc($sql, array($values));
    	
    	if ($page > 0) {
    		$res = db_pagination($sql, $perPage, $page);
    	} else {
    		$res = db_query($sql);
    	}
    	
    	return db_get_rows($res, 'DM');
    }
    
    /**
     * Returns messages sent to or received by $character
     * @param $characterA
     * @param $characterB
     * @param $page
     * @param $perPage
     * @return array of DM objects
     */
    static function getMessagesContacts(Character $character, enumDMDeliveryType $deliveryType, integer $page, integer $perPage){
    	if ($character == null) {
    		throw new CombineException('Invalid arguments supplied.');
    	}
    	 
    	$receiver = '';
    	$sender = '';
    	 
     	if ($deliveryType & enumDMDeliveryType::Received) $receiver = 'received > 0';
    	if ($deliveryType & enumDMDeliveryType::Sent) $sender = 'sent > 0';
    	
    	$values = array('handle'=>$character->handle, 'id'=>$character->entityID);
    	     	 
    	if (strlen($receiver) > 0 && strlen($sender) > 0) {
    		$filter = $receiver.' OR '.$sender;
    	} else {
    		$filter = $receiver.$sender;
    	}
    	
    	$sql = 'SELECT entity, entityType, SUM(received) as received, SUM(sent) as sent FROM
    	(
    	 SELECT receiver as entity, receiverType as entityType, COUNT(messageID) as received, 0 as sent FROM messages
    	 WHERE senderType = #cint_ENTITYTYPE_CHARACTER AND sender IN (@id, @handle)
		 GROUP BY receiver, receiverType
    	UNION
    	 SELECT sender, senderType, 0, COUNT(messageID) as sent FROM messages
    	 WHERE receiverType = #cint_ENTITYTYPE_CHARACTER AND receiver IN (@id, @handle)
		 GROUP BY sender, senderType
    	) as contacts
    	GROUP BY entity, entityType
    	HAVING '.$filter;
    			
    	$sql = db_prepare_assoc($sql, array($values));
    	 
    	if ($page > 0) {
    		$res = db_pagination($sql, $perPage, $page);
    	} else {
    		$res = db_query($sql);
    	}
    	 
    	$contacts = array();
    	$resContacts = db_get_rows($res);
    	foreach ($resContacts as $contact)
    	{
    		$key = $contact->entity.';'.$contact->entityType;
    		$contacts[$key] = array('sent'=>$contact->sent,'received'=>$contact->received);
    	}
    	
    	return $contacts;
    }
    
    static function countMessagesContacts(Character $character, enumDMDeliveryType $deliveryType) {
    	if ($character == null) {
    		throw new CombineException('Invalid arguments supplied.');
    	}
    
    	$receiver = '';
    	$sender = '';
    
    	if ($deliveryType & enumDMDeliveryType::Received) $receiver = 'SUM(received) > 0';
    	if ($deliveryType & enumDMDeliveryType::Sent) $sender = 'SUM(sent) > 0';
    	 
    	$values = array('handle'=>$character->handle, 'id'=>$character->entityID);
    
    	if (strlen($receiver) > 0 && strlen($sender) > 0) {
    		$filter = $receiver.' OR '.$sender;
    	} else {
    		$filter = $receiver.$sender;
    	}
        	 
    	$sql = 'SELECT COUNT(*) as count FROM
    	(SELECT entity, entityType, SUM(received) as received, SUM(sent) as sent FROM
    	  (
    	    SELECT receiver as entity, receiverType as entityType, COUNT(messageID) as received, 0 as sent FROM messages
    	    WHERE senderType = #cint_ENTITYTYPE_CHARACTER AND (sender IN (@id, @handle))
    	  UNION
    	    SELECT sender, senderType, 0, COUNT(messageID) as sent FROM messages
    	    WHERE receiverType = #cint_ENTITYTYPE_CHARACTER AND receiver IN (@id, @handle)
    	  ) AS contacts
    	 GROUP BY entity, entityType
    	 HAVING '.$filter.
        ') AS contactsCount';
    	     
    	$res = db_prepare( $sql, $values );
    	
    	return db_single_result($res);
    }
    
    static function sendMessage(array $receivers, Character $sender, string $communication, $forwardToEmail = true) {
    	if (count($receivers) == 0) {
    		throw new CombineException('You must supply at least one receiver for the message');
    	}
    	
    	if (StringUtil::isBlank($communication)) {
    		throw new CombineException('You must have a communication message.');
    	}
    	
    	if (StringUtil::isBlank($subject)) {
    		$subject = '(No Subject)';
    	}
    	
    	//check not spamming
    	$lastMsgStamp = DMMessageUtil::getLastMessageStamp($sender->entityID);
    	if (!isHelper($sender) && $lastMsgStamp > (CGTUtil::getCGTSeconds() - 10)) {
    		throw new CombineException('You are sending messages far too frequently, you can only send them once every 10 seconds');
    	}
    	
    	$receiverInfos = getEntityInfoByRange($receivers, enumEntityType::CHARACTER);

    	if (!isAssistant($sender) && count($receiverInfos) > 25) {
    		throw new CombineException('You cannot send messages to more than 25 people at a time.');
    	}

    	if (empty($receiverInfos)) {
    		throw new CombineException('You were unable to send the message probably as you misspelled the receivers handle.');
    	}
    	
    	foreach ($receiverInfos as $receiver) {
    		if ($receiver instanceof Faction) {
    			throw new CombineException('You cannot send messages to factions directly. (Trying to send to: ' . $receiver . ')');
    		}
    	}
    	
    	$arrReceiverHandles = array();
    	foreach ($receiverInfos as $receiver){
    		$id = DMMessageUtil::sendMessage($sender, $receiver, $communication);
    		$arrReceiverHandles[$id] = $receiver->handle;
    	}
    	 
    	$player = Player::get($sender->handle);
    	if (($player->MailMessage == 1 || $player->MailMessage == 2) && $forwardToEmail) {
    		EmailUtil::mail('Yourself', 'noreply@swcombine.com', $player->email, '' , 'Message to '.$receiver, htmlentities($communication), true);
    	}
    	 
    	//successful message
    	//newbie reward for sending a darkness message for the first time
		RewardUtil::testUniqueRewards($sender, enumRewardType::SEND_MESSAGE);
    	 
    	//reward for sending a message to your faction
    	foreach ($receiverInfos as $receiver) {
    		if ($receiver instanceof Character && !$sender->is($receiver) && $sender->sameFaction($receiver)) {
				RewardUtil::testUniqueRewards($sender, enumRewardType::SEND_MESSAGE_FACTION);
    		}
    	}
    	
    	return $arrReceiverHandles;
    }
}
